﻿Imports System.Windows.Media
Imports ESRI.ArcGIS.Carto
Imports ESRI.ArcGIS.Display
Imports ESRI.ArcGIS.Geodatabase
Imports ESRI.ArcGIS.Geometry

Public Class ParserMXD
    Private mFieldNameLower As Boolean = True
    Private mSetlayerScale As Boolean = True
    Private mSetLabel As Boolean = True
    Private mMap As IMap = Nothing
    Private tip As TextBox = Nothing
    Public MultiLayerMarkerSymbolAsImage As Boolean = False
    Public GeomFieldName As String = ""
    Sub New(map As IMap,
            Optional ByVal msgBox As TextBox = Nothing,
            Optional ByVal fieldNameToLower As Boolean = True,
            Optional ByVal setLayerScale As Boolean = True,
            Optional ByVal setLabel As Boolean = True
            )
        mMap = map
        tip = msgBox
        mFieldNameLower = fieldNameToLower
        mSetlayerScale = setLayerScale
        mSetLabel = setLabel
    End Sub
    ''' <summary>
    ''' 输出错误信息
    ''' </summary>
    ''' <param name="msg">消息</param>
    ''' <param name="isError">是否错误</param>
    ''' <param name="isWarn">是否警告</param>
    Public Sub ErrorMessage(msg As String, Optional ByVal isError As Boolean = True, Optional ByVal isWarn As Boolean = False)
        If (tip Is Nothing) Then
            Return
        End If
        If isWarn Then
            msg = String.Format("【Warn】{0}", msg)
        ElseIf (isError) Then
            msg = String.Format("【Error】{0}", msg)
        End If
        tip.AppendText(msg & vbNewLine)
    End Sub
    ''' <summary>
    ''' 图片符号设置
    ''' </summary>
    Private Class PictureSymbolSetting
        Public Folder As String = ""
        Public LayerName As String = ""
        Public PicNo As Integer = 0
    End Class
    ''' <summary>
    ''' 仅用于picturemarker图片位置存储
    ''' </summary>
    Private _picSetting As PictureSymbolSetting = Nothing
    ''' <summary>
    ''' 获取合法文件名称
    ''' </summary>
    ''' <param name="filename"></param>
    ''' <returns></returns>
    Private Function getValidFileName(filename As String) As String
        Dim invalidchar As Char() = System.IO.Path.GetInvalidFileNameChars()
        filename = filename.Replace(" ", "")
        For Each ichar In invalidchar
            If filename.Contains(ichar) Then
                filename = filename.Replace(ichar, "")
            End If
        Next
        Return filename
    End Function
    ''' <summary>
    ''' 获取所有图层
    ''' </summary>
    ''' <param name="layersDict">图层字典：图层名称-》图层</param>
    ''' <param name="layer"></param>
    ''' <param name="parentLayerName"></param>
    Private Sub getLayers(layersDict As Dictionary(Of String, ILayer), layer As ILayer, parentLayerName As String)
        If TypeOf layer Is IFeatureLayer Then
            Dim lyrname As String = layer.Name
            If Not String.IsNullOrWhiteSpace(parentLayerName) Then
                lyrname = parentLayerName & "_" & layer.Name
            End If
            If layersDict.ContainsKey(lyrname) Then
                Dim no As Integer = 0
                Dim lyrname_new As String = lyrname
                While (True)
                    If Not layersDict.ContainsKey(lyrname_new) Then
                        Exit While
                    End If
                    no += 1
                    lyrname_new = lyrname & "_重复" & no
                End While
                lyrname = lyrname_new
            End If
            layersDict.Add(lyrname, layer)
        ElseIf TypeOf layer Is ICompositeLayer Then
            Dim pComLayer As ICompositeLayer = layer
            If Not String.IsNullOrWhiteSpace(parentLayerName) Then
                parentLayerName = parentLayerName & "_" & layer.Name
            Else
                parentLayerName = layer.Name
            End If
            For i As Integer = 0 To pComLayer.Count - 1
                getLayers(layersDict, pComLayer.Layer(i), parentLayerName)
            Next
        End If
    End Sub
    ''' <summary>
    ''' 获取当前地图所有图层
    ''' </summary>
    ''' <returns></returns>
    Private Function getMapLayers() As Dictionary(Of String, ILayer)
        Dim layersDict As New Dictionary(Of String, ILayer)
        Dim layers As IEnumLayer = mMap.Layers(recursive:=False)
        layers.Reset()
        Dim layer As ILayer
        layer = layers.Next
        While (layer IsNot Nothing)
            getLayers(layersDict, layer, "")
            layer = layers.Next
        End While
        Return layersDict
    End Function
    ''' <summary>
    ''' 输出mxd符号到sld
    ''' </summary>
    ''' <param name="outSldFile">输出sld文件</param>
    ''' <param name="PreserveWhitespace">输出时是否保留空格</param>
    ''' <param name="outForOneFile">是否输出为一个文件(False：按图层输出)</param>
    ''' <param name="datasetNameAsOutName">数据集名作为输出名称（False：默认图层名称）</param>
    ''' <param name="onlyExportVisible">只输出可见图层</param>
    ''' <param name="layerNameToLower">图层名称转为小写</param>
    ''' <returns></returns>
    Public Function AnalyseLayerSymbology(outSldFile As String,
                                     PreserveWhitespace As Boolean,
                                     outForOneFile As Boolean, datasetNameAsOutName As Boolean,
                                     onlyExportVisible As Boolean,
                                     layerNameToLower As Boolean) As List(Of String)
        Dim res As New List(Of String)
        mFieldNameLower = layerNameToLower
        Dim outFolder As String = System.IO.Path.GetDirectoryName(outSldFile)
        If System.IO.Directory.Exists(outFolder) = False Then
            System.IO.Directory.CreateDirectory(outFolder)
        End If
        'Dim layers As IEnumLayer = mMap.Layers
        'Dim plyr As ILayer
        'layers.Reset()
        'plyr = layers.Next
        Dim sldLyrs As New List(Of SLDLayer)
        Dim pMapLayer As IMapLayers = mMap
        Dim layersDict = getMapLayers()
        For Each kvp In layersDict
            Dim plyr As ILayer = kvp.Value
            If Not TypeOf plyr Is IFeatureLayer Then
                Continue For
            End If
            If onlyExportVisible Then
                If pMapLayer.IsLayerVisible(plyr) = False Then
                    Continue For
                End If
            End If
            ErrorMessage(String.Format("解析图层：{0}", plyr.Name), False)
            '#################
            Dim pDataLayer As IDataLayer = plyr
            Dim pFtrclsName As IFeatureClassName = pDataLayer.DataSourceName
            Dim dsname As String = CType(pFtrclsName, IDatasetName).Name
            _picSetting = New PictureSymbolSetting
            _picSetting.Folder = outFolder
            'getValidFileName(plyr.Name) & "_" & 
            _picSetting.LayerName = CType(pFtrclsName, IDatasetName).Name
            _picSetting.PicNo = 0
            '#########################
            Dim slyr As SLDLayer = SpreadLayerStructure(plyr)
            If slyr Is Nothing Then
                Continue For
            End If
            slyr.layerPath = kvp.Key
            slyr.layerName = plyr.Name
            slyr.description = CType(plyr, ILayerGeneralProperties).LayerDescription
            '写符号
            sldLyrs.Add(slyr)
            res.Add(String.Format("图层名称：{0},要素类名称:{1}", slyr.layerPath, slyr.datasetname))
        Next
        'While (plyr IsNot Nothing)
        '    If Not TypeOf plyr Is IFeatureLayer Then
        '        plyr = layers.Next
        '        Continue While
        '    End If
        '    If onlyExportVisible Then
        '        If pMapLayer.IsLayerVisible(plyr) = False Then
        '            plyr = layers.Next
        '            Continue While
        '        End If
        '    End If
        '    ErrorMessage(String.Format("解析图层：{0}", plyr.Name), False)
        '    '#################
        '    Dim pDataLayer As IDataLayer = plyr
        '    Dim pFtrclsName As IFeatureClassName = pDataLayer.DataSourceName
        '    Dim dsname As String = CType(pFtrclsName, IDatasetName).Name
        '    _picSetting = New PictureSymbolSetting
        '    _picSetting.Folder = outFolder
        '    _picSetting.LayerName = getValidFileName(plyr.Name) & "_" & CType(pFtrclsName, IDatasetName).Name
        '    _picSetting.PicNo = 0
        '    '#########################
        '    Dim slyr As SLDLayer = SpreadLayerStructure(plyr)
        '    If slyr Is Nothing Then
        '        plyr = layers.Next
        '        Continue While
        '    End If

        '    slyr.description = CType(plyr, ILayerGeneralProperties).LayerDescription
        '    '写符号
        '    sldLyrs.Add(slyr)
        '    plyr = layers.Next
        'End While
        If sldLyrs.Count = 0 Then
            ErrorMessage(String.Format("[Warning]！！！未解析到图层！！！"), False)
        Else
            If outForOneFile Then
                Dim outSld As New OutPutSld(outSldFile, PreserveWhitespace)
                For Each slyr In sldLyrs
                    outSld.writeSldLayer(slyr)
                Next
                outSld.SaveDoc()
            Else
                For Each slyr In sldLyrs
                    Dim outFile As String
                    Dim outName As String = slyr.layerPath
                    If String.IsNullOrWhiteSpace(outName) Then
                        outName = slyr.layerName
                    End If
                    If datasetNameAsOutName Then
                        outName = slyr.datasetname
                    End If
                    outName = outName.Trim
                    If mFieldNameLower Then
                        outName = outName.ToLower
                    End If
                    outFile = System.IO.Path.Combine(outFolder, outName + ".sld")
                    Dim outSld As New OutPutSld(outFile, PreserveWhitespace)
                    outSld.writeSldLayer(slyr)
                    outSld.SaveDoc()
                Next
            End If
            ErrorMessage(String.Format("[Sucess]！！！解析完成！！！"), False)
        End If
        Return res
    End Function
    ''' <summary>
    ''' 解析图层
    ''' </summary>
    ''' <param name="layer">图层</param>
    ''' <returns>sld图层，存储sld相关信息</returns>
    Private Function SpreadLayerStructure(layer As ILayer) As SLDLayer
        If (layer Is Nothing OrElse Not TypeOf layer Is IFeatureLayer) Then
            Return Nothing
        End If
        Dim sldLyr As New SLDLayer
        Dim ftrlyr As IFeatureLayer = layer
        Dim geolyr As IGeoFeatureLayer = layer
        Dim renderer As IFeatureRenderer = geolyr.Renderer
        ' Dim symValues As List(Of SLDSymbolizer) = Nothing
        ' Dim symbolizer As New SLDSymbolizer
        Dim sldStyleTYpe As SLDStyle.SymbolizerType
        Dim pDataLayer As IDataLayer = ftrlyr
        Dim pFtrclsName As IFeatureClassName = pDataLayer.DataSourceName
        Dim ftrclsType As esriGeometryType = pFtrclsName.ShapeType
        Dim rotationField As String = ""
        If ftrclsType = esriGeometryType.esriGeometryPoint OrElse
            ftrclsType = esriGeometryType.esriGeometryMultipoint Then
            sldStyleTYpe = SLDStyle.SymbolizerType.PointSymbolizer
            If TypeOf renderer Is IRotationRenderer Then
                Dim rotationRender As IRotationRenderer = renderer
                rotationField = rotationRender.RotationField
            End If
        ElseIf ftrclsType = esriGeometryType.esriGeometryPolyline Then
            sldStyleTYpe = SLDStyle.SymbolizerType.LineSymbolizer
        ElseIf ftrclsType = esriGeometryType.esriGeometryPolygon Then
            sldStyleTYpe = SLDStyle.SymbolizerType.PolygonSymbolizer
        Else
            ErrorMessage(String.Format("图层{0}({1})几何类型不是点、线、面", layer.Name, CType(pFtrclsName, IDatasetName).Name))
            Return Nothing
        End If
        Dim dsname As String = CType(pFtrclsName, IDatasetName).Name
        Dim style As New SLDStyle(sldStyleTYpe)
        sldLyr.layerName = ftrlyr.Name
        sldLyr.datasetname = dsname
        style.styleName = dsname
        Dim minScale As Double = 0
        Dim maxScale As Double = 0
        If mSetlayerScale Then
            minScale = ftrlyr.MinimumScale
            maxScale = ftrlyr.MaximumScale
        End If
        If TypeOf renderer Is IUniqueValueRenderer Then
            SpreadUVRenderer(style, renderer, minScale, maxScale, layer， rotationField)
        ElseIf TypeOf renderer Is ISimpleRenderer Then
            '如果ISimpleRenderer无名称，则采用图层名称
            Dim pSimRenderer As ISimpleRenderer = renderer
            If String.IsNullOrWhiteSpace(pSimRenderer.Label) Then
                pSimRenderer.Label = ftrlyr.Name
            End If
            SpreadSimpleRender(style, renderer, minScale, maxScale, rotationField)

        ElseIf TypeOf renderer Is IClassBreaksRenderer Then
            SpreakdClassBreakRenderer(style, renderer, minScale, maxScale, layer, rotationField)
        Else
            ErrorMessage(String.Format("Renderer未写解析函数"))
        End If
        sldLyr.styles.Add(style)
        If mSetLabel Then
            '解析注记
            Dim labelStyle As New SLDStyle(SLDStyle.SymbolizerType.TextSymbolizer)
            labelStyle.styleName = style.styleName & "_Label"
            Dim parseLabel As New ParseLabel(mFieldNameLower, mSetlayerScale, GeomFieldName)
            parseLabel.ParseLabel(labelStyle, ftrlyr)
            If labelStyle.rules.Count > 0 Then
                sldLyr.styles.Add(labelStyle)
            End If
        End If
        Return sldLyr
    End Function
    ''' <summary>
    ''' 解析ClassBreaksRenderer
    ''' </summary>
    ''' <param name="style"></param>
    ''' <param name="pClassBreaksRenderer"></param>
    ''' <param name="minScale"></param>
    ''' <param name="maxScale"></param>
    ''' <param name="layer"></param>
    ''' <param name="rotationField"></param>
    Private Sub SpreakdClassBreakRenderer(style As SLDStyle,
                                          pClassBreaksRenderer As IClassBreaksRenderer,
                                           minScale As Double, maxScale As Double,
                                 layer As ILayer, Optional ByVal rotationField As String = "")
        If pClassBreaksRenderer Is Nothing Then
            Return
        End If
        Dim breakcount As Integer = pClassBreaksRenderer.BreakCount
        Dim fld As String = pClassBreaksRenderer.Field
        If String.IsNullOrWhiteSpace(fld) Then
            Return
        End If
        For i As Integer = 0 To breakcount - 1
            Dim value As String = pClassBreaksRenderer.Break(i)
            Dim name As String = pClassBreaksRenderer.Label(i)
            Dim rule As SLDRule = style.NewRule
            rule.ruleName = name
            rule.description = name
            setScaleOfRule(rule, minScale, maxScale)
            If i = 0 Then
                rule.sql = String.Format("{0} <={1}", fld, value)
            Else
                Dim lastvalue As Double = pClassBreaksRenderer.Break(i - 1)
                rule.sql = String.Format("{0}>{1} and {0} <={2}", fld, lastvalue, value)
            End If
            Dim symbolizer As New SLDSymbolizer()
            Dim symbol As ISymbol = pClassBreaksRenderer.Symbol(i) ' pUniqueRender.Symbol(allValues)
            If symbol IsNot Nothing Then
                SpreadSymbol(rule, symbol, rotationField)
            End If
            rule.add(symbolizer)
            style.rules.Add(rule)
        Next
    End Sub
    ''' <summary>
    ''' 解析IUniqueValueRenderer
    ''' </summary>
    ''' <param name="style"></param>
    ''' <param name="pUniqueRender"></param>
    ''' <param name="minScale"></param>
    ''' <param name="maxScale"></param>
    Private Sub SpreadUVRenderer(style As SLDStyle,
                                      pUniqueRender As IUniqueValueRenderer,
                                 minScale As Double, maxScale As Double,
                                 layer As ILayer, Optional ByVal rotationField As String = "")
        Dim allSqls As New List(Of String)
        Dim firstPos As Integer = style.rules.Count
        '唯一值符号
        Dim valueCount As Integer = pUniqueRender.ValueCount
        Dim fldCount As Integer = pUniqueRender.FieldCount
        Dim fldDelimiter As String = pUniqueRender.FieldDelimiter
        For i As Integer = 0 To valueCount - 1
            Dim allValues As String = pUniqueRender.Value(i)
            Dim allValueSplit() As String = allValues.Split(fldDelimiter)
            Dim rule As SLDRule = style.NewRule
            rule.ruleName = pUniqueRender.Label(allValues)
            rule.description = pUniqueRender.Description(allValues)
            setScaleOfRule(rule, minScale, maxScale)
            Dim sqls As New List(Of String)
            For j As Integer = 0 To fldCount - 1
                Dim fldname As String = pUniqueRender.Field(j)
                If mFieldNameLower Then
                    fldname = fldname.ToLower
                End If
                Dim fldv As String = allValueSplit(j)
                If fldv.ToLower = "<NULL>".ToLower Then
                    sqls.Add(String.Format("{0} is null", fldname))
                Else
                    sqls.Add(String.Format("{0}={1}", fldname, fldv))
                End If
            Next
            rule.sql = String.Join(" and ", sqls)
            allSqls.AddRange(sqls)
            Dim symbolizer As New SLDSymbolizer()
            Dim symbol As ISymbol = pUniqueRender.Symbol(allValues)
            If symbol IsNot Nothing Then
                SpreadSymbol(rule, symbol, rotationField)
            End If
            rule.add(symbolizer)
            style.rules.Add(rule)
        Next
        '默认值,插入第一个
        If pUniqueRender.DefaultSymbol IsNot Nothing And pUniqueRender.UseDefaultSymbol Then
            Dim defaultRule As SLDRule = style.NewRule
            defaultRule.ruleName = pUniqueRender.DefaultLabel
            If String.IsNullOrWhiteSpace(defaultRule.ruleName) Then
                defaultRule.ruleName = layer.Name
            End If
            If allSqls.Count > 0 Then
                defaultRule.sql = String.Format("not({0})", String.Join(" or ", allSqls))
            End If
            setScaleOfRule(defaultRule, minScale, maxScale)
            Dim defaultSymbolizer As New SLDSymbolizer
            SpreadSymbol(defaultRule, pUniqueRender.DefaultSymbol, rotationField)
            defaultRule.add(defaultSymbolizer)
            style.rules.Insert(firstPos, defaultRule)
        End If
    End Sub
    ''' <summary>
    ''' 解析SimpleRender
    ''' </summary>
    ''' <param name="style"></param>
    ''' <param name="renderer"></param>
    ''' <param name="minScale"></param>
    ''' <param name="maxScale"></param>
    ''' <param name="rotationField"></param>
    Private Sub SpreadSimpleRender(style As SLDStyle,
                                   renderer As ISimpleRenderer,
                                    minScale As Double, maxScale As Double,
                                   rotationField As String)
        Dim rule As SLDRule = style.NewRule
        setScaleOfRule(rule, minScale, maxScale)
        Dim objRenderer As ISimpleRenderer = renderer
        Dim symbolizer As New SLDSymbolizer()
        SpreadSymbol(rule, objRenderer.Symbol, rotationField)
        rule.ruleName = objRenderer.Label
        rule.add(symbolizer)
        style.rules.Add(rule)
    End Sub
    ''' <summary>
    ''' 设置最大最小比例
    ''' </summary>
    ''' <param name="rule"></param>
    ''' <param name="minscale"></param>
    ''' <param name="maxscale"></param>
    Private Sub setScaleOfRule(rule As SLDRule, minscale As Double, maxscale As Double)
        If minscale > 0.001 Then
            rule.add(New SLdParameter("MaxScaleDenominator", minscale, True))
        End If
        If maxscale > 0.001 Then
            rule.add(New SLdParameter("MinScaleDenominator", maxscale, True))
        End If
    End Sub
    ''' <summary>
    ''' 解析符号
    ''' </summary>
    ''' <param name="rule"></param>
    ''' <param name="sym"></param>
    ''' <param name="rotationField"></param>
    Private Sub SpreadSymbol(rule As SLDRule,
                                  sym As ISymbol,
                            Optional ByVal rotationField As String = "")
        Dim symbolizer As New SLDSymbolizer()
        If TypeOf sym Is IFillSymbol Then
            ParseFillSymbol(symbolizer, sym)
        ElseIf TypeOf sym Is IMarkerSymbol Then
            ParseMarkerSymbol(symbolizer, sym, rotationField)
        ElseIf TypeOf sym Is ILineSymbol Then
            ParseLineSymbol(symbolizer, sym)
        ElseIf sym Is Nothing Then
            ErrorMessage(String.Format("符号为nothing"))
        Else
            ErrorMessage(String.Format("符号{0}未写解析函数", CType(sym, IDisplayName).NameString))
        End If
        rule.add(symbolizer)
        ' sSym.Add(symbolizer)
        ' Return symbolizer
    End Sub

#Region "IFillSymbol"
    ''' <summary>
    ''' 解析FillSymbol
    ''' </summary>
    ''' <param name="symbolizer"></param>
    ''' <param name="fillSym"></param>
    Public Sub ParseFillSymbol(symbolizer As SLDSymbolizer,
                                     fillSym As IFillSymbol)
        If TypeOf fillSym Is ISimpleFillSymbol Then
            ParseSimpleFillSymbol(symbolizer, fillSym)
        ElseIf TypeOf fillSym Is IMarkerFillSymbol Then
            ParseMarkerFillSymbol(symbolizer, fillSym)
        ElseIf TypeOf fillSym Is IPictureFillSymbol Then
            ParsePictureFillSymbol(symbolizer, fillSym)
        ElseIf TypeOf fillSym Is ILineFillSymbol Then
            ParseLineFillSymbol(symbolizer, fillSym)
        ElseIf TypeOf fillSym Is IMultiLayerFillSymbol Then
            Dim pMultiLayerSym As IMultiLayerFillSymbol = fillSym
            Dim count As Integer = pMultiLayerSym.LayerCount
            For i As Integer = count - 1 To 0 Step -1
                If Not CType(pMultiLayerSym, ILayerVisible).LayerVisible(i) Then
                    Continue For
                End If
                Dim pSubFillSym As IFillSymbol = pMultiLayerSym.Layer(i)
                ParseFillSymbol(symbolizer, pSubFillSym)
            Next
        Else
            ErrorMessage(String.Format("符号{0}未写解析函数", CType(fillSym, IDisplayName).NameString))
        End If
    End Sub
    ''' <summary>
    ''' 解析SimpleFillSymbol
    ''' </summary>
    ''' <param name="symbolizer"></param>
    ''' <param name="sym"></param>
    Private Sub ParseSimpleFillSymbol(symbolizer As SLDSymbolizer,
                                           sym As ISimpleFillSymbol)
        Dim sldcolor As String = getStringForColor(sym.Color)
        If Not String.IsNullOrWhiteSpace(sldcolor) Then
            Dim fill As New SLDSymbol("Fill")
            fill.sldParamOrSymbols.Add(New SLdParameter("fill", sldcolor))
            symbolizer.addLayer(New SLDSymbolLayer(fill))
        End If
        'If sym.Outline.
        Dim outline As ILineSymbol = sym.Outline
        Dim sldoutlinecolor As String = getStringForColor(outline.Color)
        If (String.IsNullOrWhiteSpace(sldoutlinecolor) OrElse sym.Outline.Width <= 0.0000001) Then
            '判断是否所有边线无
            Dim isRealNoOutLine As Boolean = True
            If TypeOf outline Is IMultiLayerLineSymbol Then
                Dim pMultiLayer As IMultiLayerLineSymbol = outline
                For i As Integer = 0 To pMultiLayer.LayerCount - 1
                    Dim psym As ILineSymbol = pMultiLayer.Layer(i)
                    Dim mc As String = getStringForColor(psym.Color)
                    If Not (String.IsNullOrWhiteSpace(mc) OrElse psym.Width <= 0.0000001) Then
                        isRealNoOutLine = False
                        Exit For
                    End If
                Next
            End If
            If (isRealNoOutLine) Then
                '添加边线，否则面之间有缝隙，不知道为啥，待解决，暂时通过设置边线解决
                outline = New SimpleLineSymbol
                outline.Color = sym.Color
                outline.Width = 1
            End If
        End If
        ParseLineSymbol(symbolizer, outline)
    End Sub
    ''' <summary>
    ''' 解析MarkerFillSymbol
    ''' </summary>
    ''' <param name="symbolizer"></param>
    ''' <param name="sym"></param>
    Private Sub ParseMarkerFillSymbol(symbolizer As SLDSymbolizer,
                                      sym As IMarkerFillSymbol)
        Dim fillSym As New SLDSymbol("Fill")
        Dim graphicFillSym As New SLDSymbol("GraphicFill")
        Dim markserSymbolizer As New SLDSymbolizer
        Dim markSym As IMarkerSymbol = sym.MarkerSymbol
        Dim markerSize As Double = ParseMarkerSymbol(markserSymbolizer, markSym)
        copySymbolizerToSldSymbol(markserSymbolizer, graphicFillSym)
        fillSym.sldParamOrSymbols.Add(graphicFillSym)
        Dim lyr As New SLDSymbolLayer(fillSym)
        'space ，考虑markersize，还有些不一致，需要研究
        If Double.IsNaN(markerSize) OrElse markerSize <= 0 Then
            markerSize = SldUnit.MarkerPoint2Pixel(markSym.Size)
        End If

        Dim pFillProperties As IFillProperties = sym
        Dim xSpace As Double = pFillProperties.XSeparation - markerSize
        Dim ySpace As Double = pFillProperties.YSeparation - markerSize
        Dim top As Double = 0
        Dim left As Double = 0
        Dim right As Double = 0
        Dim bottom As Double = 0
        If xSpace < 0 Then
            xSpace = 0
        End If
        If ySpace < 0 Then
            ySpace = 0
        End If
        If xSpace > 0 Or ySpace > 0 Then
            Dim offsetx As Double = pFillProperties.XOffset
            Dim offsety As Double = pFillProperties.YOffset
            If offsetx < 0 AndAlso xSpace > 0 Then
                Dim n As Integer = Math.Ceiling(-offsetx / xSpace)
                offsetx = xSpace * n + offsetx
            End If
            If offsety < 0 AndAlso ySpace > 0 Then
                Dim n As Integer = Math.Ceiling(-offsety / ySpace)
                offsety = ySpace * n + offsety
            End If
            top = ySpace - offsety
            left = offsetx
            right = xSpace - offsetx
            bottom = offsety
        End If

        If Math.Abs(top) > 0 OrElse Math.Abs(left) > 0 OrElse Math.Abs(right) > 0 OrElse Math.Abs(bottom) > 0 Then
            Dim offsetpara As SLdParameter = New SLdParameter("graphic-margin", String.Format("{0} {1} {2} {3}", top, right, bottom, left),
                                   False,
                                   "VendorOption")
            lyr.SymbolsOrParas.Add(offsetpara)
        End If
        symbolizer.layers.Add(lyr)
        'stroke
        ParseLineSymbol(symbolizer, sym.Outline)
    End Sub
    ''' <summary>
    ''' 解析PictureFillSymbol
    ''' </summary>
    ''' <param name="symbolizer"></param>
    ''' <param name="sym"></param>
    Private Sub ParsePictureFillSymbol(symbolizer As SLDSymbolizer,
                                      sym As IPictureFillSymbol)
        Dim fillSym As New SLDSymbol("Fill")
        Dim graphicFillSym As New SLDSymbol("GraphicFill")
        Dim pic As stdole.Picture = sym.Picture
        Dim picWidth As Integer = 0
        Dim picHeight As Integer = 0

        Dim picName As String = getPictureName(pic, sym.BitmapTransparencyColor, picWidth, picHeight)
        Dim picSize As Double = Math.Max(picWidth, picHeight)
        Dim scale As Double = Math.Max(sym.XScale, sym.YScale)
        'marker fill不设间距，参考arcgis
        Dim pFillProperties As IFillProperties = sym
        Dim sep As Double = Math.Max(pFillProperties.XSeparation, pFillProperties.YSeparation)
        Dim size As Double = picSize * scale + sep
        Dim mSym As SLDSymbol = getPictureGraphic(picName, size, sym.Angle)
        graphicFillSym.sldParamOrSymbols.Add(mSym)
        fillSym.sldParamOrSymbols.Add(graphicFillSym)
        Dim lyr As New SLDSymbolLayer(fillSym)
        symbolizer.layers.Add(lyr)
        'stroke
        ParseLineSymbol(symbolizer, sym.Outline)
    End Sub
    ''' <summary>
    ''' 解析LineFillSymbol
    ''' </summary>
    ''' <param name="symbolizer"></param>
    ''' <param name="sym"></param>
    Private Sub ParseLineFillSymbol(symbolizer As SLDSymbolizer,
                                      sym As ILineFillSymbol)
        Dim angle As Double = sym.Angle
        Dim space As Double = getRotateSize(sym.Separation, angle)
        ParseFillLineSymbol(symbolizer, angle, space, sym.LineSymbol)
        'stroke
        ParseLineSymbol(symbolizer, sym.Outline)
    End Sub
#Region "解析fillline,通过wkt实现角度"
    Private Sub ParseFillLineSymbol(symbolizer As SLDSymbolizer,
                                    angle As Double,
                                    space As Double,
                                    lineSym As ILineSymbol)
        If TypeOf lineSym Is IMultiLayerLineSymbol Then
            Dim pMultiLayerSym As IMultiLayerLineSymbol = lineSym
            Dim count As Integer = pMultiLayerSym.LayerCount
            For i As Integer = count - 1 To 0 Step -1
                Dim pSubLineSym As ILineSymbol = pMultiLayerSym.Layer(i)
                ParseFillLineSymbol(symbolizer, angle, space, pSubLineSym)
            Next
        Else
            ParseFillSimpleLineSymbolOfNotMultiLyers(symbolizer, angle, space, lineSym)
        End If
    End Sub
#Region "获取线的wkt字符串"
    Private Function getWKTWellKnownNameOfLineSymbol(angle As Double) As String
        If (Math.Abs(angle) < 0.0001) Then
            Return "wkt://MULTILINESTRING((0 0,1 0))"
        End If
        Dim pLine As ILine = New Line
        Dim fpt As IPoint = New ESRI.ArcGIS.Geometry.Point()
        fpt.PutCoords(0, 0)
        Dim tpt As IPoint = New ESRI.ArcGIS.Geometry.Point
        tpt.PutCoords(100, 0)
        pLine.FromPoint = fpt
        pLine.ToPoint = tpt
        Dim pTransForm As ITransform2D = pLine
        pTransForm.Rotate(fpt, angle * Math.PI / 180)
        tpt = pLine.ToPoint
        'wkt必须在0-1范围（可大不可小，小了就不满）
        Dim wkt As String = String.Format("wkt://MULTILINESTRING((0 0,{0} {1}))", Math.Round(tpt.X, 3), Math.Round(tpt.Y, 3))
        Return wkt
    End Function
    Private Function getWKTWellKnownNameOfCartographicLineSymbol(angle As Double,
                                                    lineSym As ICartographicLineSymbol) As String

        Dim pLineProperties As ILineProperties = lineSym
        Dim pTemplate As ITemplate = pLineProperties.Template
        If pTemplate Is Nothing OrElse pTemplate.PatternElementCount = 0 Then
            Return getWKTWellKnownNameOfLineSymbol(angle)
        End If
        ErrorMessage(String.Format("符号ICartographicLineSymbol未写解析函数"), isError:=False, isWarn:=True)
        'Return "error parse ICartographicLineSymbol"
        '有问题，待研究
        Dim pEleCount As Integer = pTemplate.PatternElementCount
        Dim polyline As IPolyline = New Polyline
        Dim geoCol As IGeometryCollection = polyline
        Dim startPos As Integer = 0
        For i As Integer = 0 To pEleCount - 1
            Dim mark As Double
            Dim gap As Double
            pTemplate.GetPatternElement(i, mark, gap)
            If (mark = 0) Then
                startPos += mark + gap
                Continue For
            End If
            Dim ppath As IPath = New Path
            Dim fpt As IPoint = New Point
            Dim tpt As IPoint = New Point
            fpt.PutCoords(startPos, 0)
            tpt.PutCoords(startPos + mark, 0)
            ppath.FromPoint = fpt
            ppath.ToPoint = tpt
            geoCol.AddGeometry(ppath)
            startPos += mark + gap
        Next
        Dim pt0 As IPoint = New Point
        pt0.PutCoords(0, 0)
        Dim pTransForm As ITransform2D = polyline
        pTransForm.Rotate(pt0, angle * Math.PI / 180)

        Dim len As Double = Math.Max(polyline.Envelope.Width, polyline.Envelope.Height)
        Dim sx As Double = 1 / len
        Dim sy As Double = 1 / len
        pTransForm.Scale(pt0, sx, sy)

        Dim geoCount As Integer = geoCol.GeometryCount
        Dim wktLines As New List(Of String)
        For i As Integer = 0 To geoCount - 1
            Dim ppath As IPath = geoCol.Geometry(i)
            Dim fpt As IPoint = ppath.FromPoint
            Dim tpt As IPoint = ppath.ToPoint
            wktLines.Add(String.Format("({0} {1},{2} {3})", Math.Round(fpt.X, 3), Math.Round(fpt.Y, 3), Math.Round(tpt.X, 3), Math.Round(tpt.Y, 3)))
        Next
        'wkt必须在0-1范围（可大不可小，小了就不满）
        Dim wkt As String = String.Format("wkt://MULTILINESTRING({0})", String.Join(",", wktLines))
        Return wkt
    End Function
#End Region
    ''' <summary>
    ''' 根据旋转角度和size获取旋转后的大小
    ''' </summary>
    ''' <param name="size"></param>
    ''' <param name="angle"></param>
    ''' <returns></returns>
    Private Function getRotateSize(size As Double, angle As Double) As Double
        If (Math.Abs(angle) < 0.0001) Then
            Return size
        End If
        Dim pts As IPointCollection = New Polyline
        Dim pt As IPoint
        'vertex
        pt = New Point
        pt.PutCoords(0, 0)
        pts.AddPoint(pt)
        'vertex
        pt = New Point
        pt.PutCoords(0, size)
        pts.AddPoint(pt)
        'vertex
        pt = New Point
        pt.PutCoords(size, size)
        pts.AddPoint(pt)
        'vertex
        pt = New Point
        pt.PutCoords(size, 0)
        pts.AddPoint(pt)
        'vertex
        pt = New Point
        pt.PutCoords(0, 0)
        pts.AddPoint(pt)

        Dim pTransform As ITransform2D = pts
        pTransform.Rotate(pts.Point(0), angle * Math.PI / 180)
        Dim pLine As IPolyline = pts
        Dim env As IEnvelope = pLine.Envelope
        Dim nangle As Double = Math.Max(env.Width, env.Height)
        Return Math.Round(nangle, 2)
    End Function
    Private Sub ParseFillSimpleLineSymbolOfNotMultiLyers(symbolizer As SLDSymbolizer,
                                          angle As Double,
                                          space As Double,
                                          sym As ILineSymbol)
        Dim fillSym As New SLDSymbol("Fill")
        Dim graphicFillSym As New SLDSymbol("GraphicFill")
        Dim graphicSym As New SLDSymbol("Graphic")
        Dim markSym As New SLDSymbol("Mark")
        Dim wellKonwName As String = sym.GetType().ToString
        If (TypeOf sym Is ISimpleLineSymbol) Then
            wellKonwName = getWKTWellKnownNameOfLineSymbol(angle)
        ElseIf (TypeOf sym Is ICartographicLineSymbol) Then
            wellKonwName = getWKTWellKnownNameOfCartographicLineSymbol(angle, sym)
        Else
            ErrorMessage(String.Format("符号{0}未写解析函数", CType(sym, IDisplayName).NameString))
        End If
        markSym.sldParamOrSymbols.Add(New SLdParameter("WellKnownName", wellKonwName, True))
        'stroke

        Dim color As String = getStringForColor(sym.Color)
        If Not String.IsNullOrWhiteSpace(color) Then
            Dim strokeSym As New SLDSymbol("Stroke")
            strokeSym.sldParamOrSymbols.Add(New SLdParameter("stroke", color))
            strokeSym.sldParamOrSymbols.Add(New SLdParameter("stroke-width", SldUnit.Point2Pixel(sym.Width)))
            'add stroke
            markSym.sldParamOrSymbols.Add(strokeSym)
        End If
        graphicSym.sldParamOrSymbols.Add(markSym)
        graphicSym.sldParamOrSymbols.Add(New SLdParameter("Size", space, True))
        graphicFillSym.sldParamOrSymbols.Add(graphicSym)
        fillSym.sldParamOrSymbols.Add(graphicFillSym)
        Dim lyr As New SLDSymbolLayer(fillSym)
        symbolizer.layers.Add(lyr)
    End Sub
#End Region
#End Region

#Region "ILineSymbol"
    Private Sub ParseLineSymbol(symbolizer As SLDSymbolizer,
                                     lineSym As ILineSymbol)
        If TypeOf lineSym Is ISimpleLineSymbol Then
            ParseSimpleLineSymbol(symbolizer, lineSym)
        ElseIf TypeOf lineSym Is IMarkerLineSymbol Then
            ParseMarkerLineSymbol(symbolizer, lineSym)
        ElseIf TypeOf lineSym Is IHashLineSymbol Then
            ParseHashLineSymbol(symbolizer, lineSym)
        ElseIf TypeOf lineSym Is ICartographicLineSymbol Then
            ParseCartographicLineSymbol(symbolizer, lineSym)
        ElseIf TypeOf lineSym Is IMultiLayerLineSymbol Then
            Dim pMultiLayerSym As IMultiLayerLineSymbol = lineSym
            Dim count As Integer = pMultiLayerSym.LayerCount
            For i As Integer = count - 1 To 0 Step -1
                If Not CType(pMultiLayerSym, ILayerVisible).LayerVisible(i) Then
                    Continue For
                End If
                Dim pSubLineSym As ILineSymbol = pMultiLayerSym.Layer(i)

                ParseLineSymbol(symbolizer, pSubLineSym)
            Next
        Else
            ErrorMessage(String.Format("符号{0}未写解析函数", CType(lineSym, IDisplayName).NameString))
        End If
    End Sub
    Private Sub ParseSimpleLineSymbol(symbolizer As SLDSymbolizer,
                                           sym As ISimpleLineSymbol)
        Dim sldcolor As String = getStringForColor(sym.Color)
        If (String.IsNullOrWhiteSpace(sldcolor)) Then
            Return
        End If
        Dim res As New SLDSymbol("Stroke")
        Dim width As Double = sym.Width
        res.sldParamOrSymbols.Add(New SLdParameter("stroke-width", SldUnit.Point2Pixel(width)))
        res.sldParamOrSymbols.Add(New SLdParameter("stroke", sldcolor))
        symbolizer.addLayer(New SLDSymbolLayer(res))
    End Sub
    Private Sub ParseCartographicLineSymbol(symbolizer As SLDSymbolizer,
                                           sym As ICartographicLineSymbol)
        Dim sldcolor As String = getStringForColor(sym.Color)
        If (String.IsNullOrWhiteSpace(sldcolor)) Then
            Return
        End If
        Dim strokeSymbol As New SLDSymbol("Stroke")
        Dim width As Double = sym.Width
        strokeSymbol.sldParamOrSymbols.Add(New SLdParameter("stroke-width", SldUnit.Point2Pixel(width)))
        strokeSymbol.sldParamOrSymbols.Add(New SLdParameter("stroke", sldcolor))
        setCartographicLineStrokeProperties(strokeSymbol, sym, Nothing)
        Dim lyr As New SLDSymbolLayer(strokeSymbol)
        setCartographicLineSymbolizerProprties(lyr, sym)

        symbolizer.addLayer(lyr)
    End Sub
    Private Sub ParseMarkerLineSymbol(symbolizer As SLDSymbolizer,
                                           sym As ICartographicLineSymbol)
        Dim pMarkerSym As IMarkerLineSymbol = sym
        Dim markserSymbolizer As New SLDSymbolizer
        Dim markSym As IMarkerSymbol = pMarkerSym.MarkerSymbol
        ParseMarkerSymbol(markserSymbolizer, markSym)
        'copySymbolizerToSldSymbol(markserSymbolizer, graphicFillSym)
        'copy##########
        Dim lyrs As List(Of SLDSymbolLayer) = markserSymbolizer.layers
        For Each marklyr In lyrs
            Dim sldsymbols As List(Of Object) = marklyr.SymbolsOrParas
            For Each sldsym In sldsymbols
                '写入图层
                Dim strokeSym As New SLDSymbol("Stroke")
                Dim graphicFillSym As New SLDSymbol("GraphicStroke")
                graphicFillSym.sldParamOrSymbols.Add(sldsym)
                strokeSym.sldParamOrSymbols.Add(graphicFillSym)
                ''################
                setCartographicLineStrokeProperties(strokeSym, sym, markSym)
                Dim lyr As New SLDSymbolLayer(strokeSym)
                setCartographicLineSymbolizerProprties(lyr, sym)
                symbolizer.addLayer(lyr)
            Next
        Next
    End Sub
    Private Sub ParseHashLineSymbol(symbolizer As SLDSymbolizer,
                                           sym As IHashLineSymbol)
        Dim angle As Double = sym.Angle - 90
        Dim size As Double = sym.Width
        Dim sldcolor As String = getStringForColor(sym.Color)
        Dim width As Double = sym.HashSymbol.Width
        If (String.IsNullOrWhiteSpace(sldcolor)) Then
            Return
        End If
        Dim strokeSymbol As New SLDSymbol("Stroke")
        Dim graphicStrokeSym As New SLDSymbol("GraphicStroke")
        Dim graphiSym As New SLDSymbol("Graphic")
        Dim markSym As New SLDSymbol("Mark")
        Dim markStroke As New SLDSymbol("Stroke")
        markStroke.sldParamOrSymbols.Add(New SLdParameter("stroke", sldcolor))
        markStroke.sldParamOrSymbols.Add(New SLdParameter("stroke-width", SldUnit.Point2Pixel(width)))
        markSym.sldParamOrSymbols.Add(New SLdParameter("WellKnownName", "shape://vertline", True))
        markSym.sldParamOrSymbols.Add(markStroke)
        graphiSym.sldParamOrSymbols.Add(markSym)
        graphiSym.sldParamOrSymbols.Add(New SLdParameter("Size", SldUnit.MarkerPoint2Pixel(size), True))
        Dim rotation As Double = getRotation(angle)
        If Math.Abs(rotation) > 0.0001 Then
            graphiSym.sldParamOrSymbols.Add(New SLdParameter("Rotation", getRotation(angle), True))
        End If
        graphicStrokeSym.sldParamOrSymbols.Add(graphiSym)
        strokeSymbol.sldParamOrSymbols.Add(graphicStrokeSym)

        Dim lyr As New SLDSymbolLayer(strokeSymbol)
        setCartographicLineSymbolizerProprties(lyr, sym)
        symbolizer.addLayer(lyr)
    End Sub
    Private Sub setCartographicLineSymbolizerProprties(lyr As SLDSymbolLayer,
                                       pLineProperties As ILineProperties)
        Dim offset As Double = 0
        offset = pLineProperties.Offset
        If (Math.Abs(offset) > 0.00001) Then
            lyr.SymbolsOrParas.Add(New SLdParameter("PerpendicularOffset", offset, True))
        End If
    End Sub
    Private Sub setCartographicLineStrokeProperties(strokeSym As SLDSymbol,
                                    sym As ICartographicLineSymbol,
                                                    markSym As IMarkerSymbol)
        Dim pLineProperties As ILineProperties = sym
        '################
        Select Case sym.Cap
            Case esriLineCapStyle.esriLCSButt
                strokeSym.sldParamOrSymbols.Add(New SLdParameter("stroke-linecap", "butt"))
            Case esriLineCapStyle.esriLCSRound
                strokeSym.sldParamOrSymbols.Add(New SLdParameter("stroke-linecap", "round"))
            Case esriLineCapStyle.esriLCSSquare
                strokeSym.sldParamOrSymbols.Add(New SLdParameter("stroke-linecap", "square"))
        End Select
        Select Case sym.Join
            Case esriLineJoinStyle.esriLJSBevel
                strokeSym.sldParamOrSymbols.Add(New SLdParameter("stroke-linejoin", "bevel"))
            Case esriLineJoinStyle.esriLJSMitre
                strokeSym.sldParamOrSymbols.Add(New SLdParameter("stroke-linejoin", "mitre"))
            Case esriLineJoinStyle.esriLJSRound
                strokeSym.sldParamOrSymbols.Add(New SLdParameter("stroke-linejoin", "round"))
        End Select
        Dim minsize As Double = -9999
        If markSym IsNot Nothing Then
            minsize = markSym.Size * 2 / 3
        End If
        Dim dashArray As String = getDasharray(pLineProperties.Template, minsize)
        If Not String.IsNullOrWhiteSpace(dashArray) Then
            strokeSym.sldParamOrSymbols.Add(New SLdParameter("stroke-dasharray", dashArray))
        End If
    End Sub
    Private Function getDasharray(pTemplate As ITemplate, Optional ByVal minMarkSize As Double = -99999) As String
        If pTemplate Is Nothing Then
            Return ""
        End If
        Dim pEleCount As Integer = pTemplate.PatternElementCount
        Dim interval As Integer = pTemplate.Interval
        Dim pArrays As New List(Of Integer)
        For i As Integer = 0 To pEleCount - 1
            Dim mark As Double
            Dim gap As Double
            pTemplate.GetPatternElement(i, mark, gap)
            Dim markLast As Double = mark * interval
            '主要线注记填充，如果marksize比符号的一半还小，则不会显示，不知道为啥，以后研究
            If minMarkSize > markLast Then
                markLast = minMarkSize
            End If
            pArrays.Add(markLast)
            pArrays.Add(gap * interval)
        Next
        Return String.Join(" ", pArrays).Trim
    End Function
#End Region

#Region "IMarkerSymbol"
    Private Function ParseMarkerSymbol(symbolizer As SLDSymbolizer,
                                     markSym As IMarkerSymbol,
                                  Optional ByVal rotationField As String = "") As Double
        Dim marksersize As Double = markSym.Size
        Dim symbols As New List(Of SLDSymbol)
        If TypeOf markSym Is ISimpleMarkerSymbol Then
            marksersize = ParseSimpleMarkerSymbol(symbolizer, markSym, rotationField)
        ElseIf TypeOf markSym Is ICharacterMarkerSymbol Then
            ParseCharcterMarkerSymbol(symbolizer, markSym, rotationField)
        ElseIf TypeOf markSym Is IPictureMarkerSymbol Then
            ParseMarkerSymbolAsImage(symbolizer, markSym, rotationField)
            'ParseMarkerPictureMarkerSymbol(symbolizer, markSym, rotationField)
        ElseIf TypeOf markSym Is IMultiLayerMarkerSymbol Then
            Dim pMultiLayerSym As IMultiLayerMarkerSymbol = markSym
            Dim count As Integer = pMultiLayerSym.LayerCount
            '判读是否全部是simplemarker,全部是simple marker，则直接解析符号；
            '不全是simple marker symbol，则输出图片，用图片符号；
            '多图层的ICharacterMarkerSymbol解析到geoserver出错（位置始终不正确），暂时通过导出图片符号实现，待解决
            Dim isAllSimple As Boolean = True
            Dim visibleCount As Integer = 0
            For i As Integer = count - 1 To 0 Step -1
                If Not CType(pMultiLayerSym, ILayerVisible).LayerVisible(i) Then
                    Continue For
                End If
                visibleCount += 1
                Dim pSubMarkerym As IMarkerSymbol = pMultiLayerSym.Layer(i)
                If Not (TypeOf pSubMarkerym Is ISimpleMarkerSymbol) Then
                    isAllSimple = False
                End If
            Next
            If MultiLayerMarkerSymbolAsImage AndAlso
                isAllSimple = False AndAlso visibleCount > 1 Then
                '多个,并且不全是simple symbol
                ParseMarkerSymbolAsImage(symbolizer, markSym, rotationField)
            Else
                For i As Integer = count - 1 To 0 Step -1
                    If Not CType(pMultiLayerSym, ILayerVisible).LayerVisible(i) Then
                        Continue For
                    End If
                    Dim pSubMarkerym As IMarkerSymbol = pMultiLayerSym.Layer(i)
                    ParseMarkerSymbol(symbolizer, pSubMarkerym, rotationField)
                Next
            End If
        ElseIf TypeOf markSym Is IArrowMarkerSymbol Then
            ParseMarkerSymbolAsImage(symbolizer, markSym, rotationField)
        Else
            ErrorMessage(String.Format("符号{0}未写解析函数", CType(markSym, IDisplayName).NameString))
        End If
        Return marksersize
    End Function
    Private Function ParseSimpleMarkerSymbol(symbolizer As SLDSymbolizer,
                                     simpleMarkerSym As ISimpleMarkerSymbol,
                                        Optional ByVal rotationField As String = "") As Double
        Dim graphicSym As New SLDSymbol("Graphic")
        Dim markSym As New SLDSymbol("Mark")
        Dim wekkKonwnname As String = getWellKnownName(simpleMarkerSym)
        If (Not String.IsNullOrWhiteSpace(wekkKonwnname)) Then
            markSym.sldParamOrSymbols.Add(New SLdParameter("WellKnownName", wekkKonwnname, True))
        End If
        'fill
        Dim sldcolor As String = getStringForColor(simpleMarkerSym.Color)
        If Not String.IsNullOrWhiteSpace(sldcolor) Then
            Dim fillSym As New SLDSymbol("Fill")
            fillSym.sldParamOrSymbols.Add(New SLdParameter("fill", sldcolor))
            markSym.sldParamOrSymbols.Add(fillSym)
        End If
        '
        Dim outlinecolor As String = getStringForColor(simpleMarkerSym.OutlineColor)
        Dim markerColor As String = getStringForColor(simpleMarkerSym.Color)
        If (simpleMarkerSym.Outline AndAlso Not String.IsNullOrWhiteSpace(outlinecolor)) Then
            Dim stokeSym As New SLDSymbol("Stroke")
            stokeSym.sldParamOrSymbols.Add(New SLdParameter("stroke", outlinecolor))
            stokeSym.sldParamOrSymbols.Add(New SLdParameter("stroke-width", SldUnit.Point2Pixel(simpleMarkerSym.OutlineSize)))
            markSym.sldParamOrSymbols.Add(stokeSym)
        Else
            If (Not String.IsNullOrWhiteSpace(markerColor)) Then
                Dim fillStokeSym As New SLDSymbol("Stroke")
                fillStokeSym.sldParamOrSymbols.Add(New SLdParameter("stroke", markerColor))
                markSym.sldParamOrSymbols.Add(fillStokeSym)
            End If
        End If
        graphicSym.sldParamOrSymbols.Add(markSym)
        'circle,square必须大小为3的倍数，不然显示不正确，不知道为啥，暂时设置为3的倍数
        Dim marksersize As Double = SldUnit.MarkerPoint2Pixel(simpleMarkerSym.Size)
        marksersize = Math.Ceiling(marksersize / 3.0) * 3
        graphicSym.sldParamOrSymbols.Add(New SLdParameter("Size", marksersize, True))
        Dim faa As Object = getRotationByFieldAndAngle(simpleMarkerSym.Angle, rotationField)
        If faa IsNot Nothing Then
            graphicSym.sldParamOrSymbols.Add(faa)
        End If
        'If String.IsNullOrWhiteSpace(rotationField) Then
        '    If Math.Abs(simpleMarkerSym.Angle) > 0 Then
        '        graphicSym.sldParamOrSymbols.Add(New SLdParameter("Rotation", getRotation(simpleMarkerSym.Angle), True))
        '    End If
        'Else
        '    If Math.Abs(simpleMarkerSym.Angle) > 0 Then
        '        graphicSym.sldParamOrSymbols.Add(New SLdParameter("Rotation", getRotation(simpleMarkerSym.Angle), True))
        '    Else
        '        Dim rotationSym As New SLDSymbol("Rotation")
        '        rotationSym.sldParamOrSymbols.Add(New SLdParameter("PropertyName", rotationField, True, ogcPrefix:=True))
        '        graphicSym.sldParamOrSymbols.Add(rotationSym)
        '    End If
        'End If
        Dim dispment As SLDSymbol = getDisplaceMent(simpleMarkerSym.XOffset, simpleMarkerSym.YOffset)
        If dispment IsNot Nothing Then
            graphicSym.sldParamOrSymbols.Add(dispment)
        End If
        symbolizer.addLayer(New SLDSymbolLayer(graphicSym))
        Return marksersize
    End Function
    Private Function getRotationByFieldAndAngle(angle As Double, rotationField As String)
        Dim faa As Object = Nothing
        If String.IsNullOrWhiteSpace(rotationField) Then
            If Math.Abs(angle) > 0 Then
                faa = New SLdParameter("Rotation", getRotation(angle), True)
            End If
        Else
            If Math.Abs(angle) > 0 Then
                Dim rotationSym As New SLDSymbol("Rotation")
                Dim addSym As New SLDSymbol("Add", True)
                Dim PropertyNameSym As New SLdParameter("PropertyName", rotationField, True, ogcPrefix:=True)
                '必须设置为减去angle，角度才正确
                Dim literPara As New SLdParameter("Literal", getRotation(angle), True, ogcPrefix:=True)
                addSym.sldParamOrSymbols.Add(PropertyNameSym)
                addSym.sldParamOrSymbols.Add(literPara)
                rotationSym.sldParamOrSymbols.Add(addSym)
                faa = rotationSym
            Else
                Dim rotationSym As New SLDSymbol("Rotation")
                rotationSym.sldParamOrSymbols.Add(New SLdParameter("PropertyName", rotationField, True, ogcPrefix:=True))
                faa = rotationSym
            End If
        End If
        Return faa
    End Function
    Private Function getDisplaceMent(xoffset As Double, yoffset As Double) As SLDSymbol
        If Math.Abs(xoffset) < 0.00001 AndAlso Math.Abs(yoffset) < 0.00001 Then
            Return Nothing
        End If
        Dim displacement As New SLDSymbol("Displacement")
        If Not Double.IsNaN(xoffset) Then
            displacement.sldParamOrSymbols.Add(New SLdParameter("DisplacementX", SldUnit.Point2Pixel(xoffset), True))
        End If
        If Not Double.IsNaN(yoffset) Then
            displacement.sldParamOrSymbols.Add(New SLdParameter("DisplacementY", SldUnit.Point2Pixel(yoffset), True))
        End If
        Return displacement
    End Function
    Private Sub ParseCharcterMarkerSymbol(symbolizer As SLDSymbolizer,
                                     simpleMarkerSym As ICharacterMarkerSymbol,
                                          Optional ByVal rotationField As String = "")
        Dim graphicSym As New SLDSymbol("Graphic")
        Dim markSym As New SLDSymbol("Mark")
        Dim wekkKonwnname As String = getFontWellKnownName(simpleMarkerSym)
        If (Not String.IsNullOrWhiteSpace(wekkKonwnname)) Then
            markSym.sldParamOrSymbols.Add(New SLdParameter("WellKnownName", wekkKonwnname, True))
        End If
        Dim sldcolor As String = getStringForColor(simpleMarkerSym.Color)
        If Not String.IsNullOrWhiteSpace(sldcolor) Then
            Dim fillSym As New SLDSymbol("Fill")
            fillSym.sldParamOrSymbols.Add(New SLdParameter("fill", sldcolor))
            markSym.sldParamOrSymbols.Add(fillSym)
        End If
        graphicSym.sldParamOrSymbols.Add(markSym)
        graphicSym.sldParamOrSymbols.Add(New SLdParameter("Size", SldUnit.MarkerPoint2Pixel(simpleMarkerSym.Size), True))
        Dim faa As Object = getRotationByFieldAndAngle(simpleMarkerSym.Angle, rotationField)
        If faa IsNot Nothing Then
            graphicSym.sldParamOrSymbols.Add(faa)
        End If
        'If Math.Abs(simpleMarkerSym.Angle) > 0 Then
        '    graphicSym.sldParamOrSymbols.Add(New SLdParameter("Rotation", getRotation(simpleMarkerSym.Angle), True))
        'End If
        Dim font As stdole.IFontDisp = simpleMarkerSym.Font
        Dim characterOffset As Double() = getFontCharacterOffset(font.Name, font.Size, simpleMarkerSym.CharacterIndex)
        Dim dispment As SLDSymbol = getDisplaceMent(simpleMarkerSym.XOffset + characterOffset(0), simpleMarkerSym.YOffset + characterOffset(1))
        If dispment IsNot Nothing Then
            graphicSym.sldParamOrSymbols.Add(dispment)
        End If
        symbolizer.addLayer(New SLDSymbolLayer(graphicSym))
    End Sub
    Private Function GetFontFromIFontDisp(pFontDisp As stdole.IFontDisp) As System.Drawing.Font
        Dim pName As String
        Dim pSize As Single
        Dim pFontStyle As System.Drawing.FontStyle
        Dim pFont As System.Drawing.Font
        pName = pFontDisp.Name
        pSize = pFontDisp.Size
        If pFontDisp.Bold = True Then
            pFontStyle = pFontStyle + System.Drawing.FontStyle.Bold
        End If
        If pFontDisp.Italic = True Then
            pFontStyle = pFontStyle + System.Drawing.FontStyle.Italic
        End If
        If pFontDisp.Strikethrough = True Then
            pFontStyle = pFontStyle + System.Drawing.FontStyle.Strikeout
        End If
        If pFontDisp.Underline = True Then
            pFontStyle = pFontStyle + System.Drawing.FontStyle.Underline
        End If
        pFont = New System.Drawing.Font(pName, pSize, pFontStyle)
        Return pFont
    End Function
    Private Function getFontCharacterOffset(fontname As String,
                                   fontSize As Double,
                                   chaIndex As Integer) As Double()
        Dim pFontConverter As FontFamilyConverter = New FontFamilyConverter()
        Dim pFontFamily As FontFamily = pFontConverter.ConvertFrom(fontname)
        Dim typefaces As ICollection(Of Typeface) = pFontFamily.GetTypefaces()
        For Each typeface In typefaces
            Dim glyph As GlyphTypeface = Nothing
            If Not typeface.TryGetGlyphTypeface(glyph) Then
                Continue For
            End If
            Dim ctgm As IDictionary(Of Integer, UShort) = glyph.CharacterToGlyphMap
            If Not ctgm.ContainsKey(chaIndex) Then
                Continue For
            End If
            ' Dim index As Integer = 70
            Dim key As UShort
            Dim ration As Double = 1 ' 2048
            key = ctgm.Item(chaIndex)
            Dim lsb As Double = glyph.LeftSideBearings.Item(key) * ration
            Dim rsb As Double = glyph.RightSideBearings.Item(key) * ration
            Dim aw As Double = glyph.AdvanceWidths.Item(key) * ration
            Dim ah As Double = glyph.AdvanceHeights.Item(key) * ration
            Dim bsb As Double = glyph.BottomSideBearings.Item(key) * ration
            Dim tsb As Double = glyph.TopSideBearings.Item(key) * ration
            Dim charWidth As Double = aw - rsb - lsb
            Dim charHeight As Double = ah - bsb - tsb
            Dim maxWorH As Double = Math.Max(charWidth, charHeight)
            Dim deltax As Double = lsb '+ charWidth / 2 - aw / 2
            Dim deltay As Double = 0  '  bsb + charHeight / 2 - ah / 2
            Dim xoffset As Double = (deltax * fontSize) / maxWorH
            Dim yoffset As Double = (deltay * fontSize) / maxWorH
            Return {xoffset, yoffset}
        Next
        Return {0, 0}
    End Function
    Private Sub ParseMarkerSymbolAsImage(symbolizer As SLDSymbolizer,
                                     symbol As IMarkerSymbol,
                                         Optional ByVal rotationField As String = "")
        _picSetting.PicNo += 1
        Dim picName As String = String.Format("pic_{0}_{1}.png", _picSetting.LayerName, _picSetting.PicNo) ' "pic_" & Guid.NewGuid().ToString.Replace("-", "") & ".png"
        Dim fpath As String = System.IO.Path.Combine(_picSetting.Folder, picName)
        Dim bitmap As Bitmap = SymbolToImage.GetImageFromSymbol(symbol)
        bitmap.Save(fpath, System.Drawing.Imaging.ImageFormat.Png)
        bitmap.Dispose()
        '
        Dim graphicSym As SLDSymbol = getPictureGraphic(picName,
                                                        symbol.Size, 0, rotationField)
        symbolizer.addLayer(New SLDSymbolLayer(graphicSym))
    End Sub
    Private Sub ParseMarkerPictureMarkerSymbol(symbolizer As SLDSymbolizer,
                                     pictureMarkerSym As IPictureMarkerSymbol,
                                               Optional ByVal rotationField As String = "")
        Dim picName As String = getPictureName(pictureMarkerSym.Picture, pictureMarkerSym.BitmapTransparencyColor)
        Dim graphicSym As SLDSymbol = getPictureGraphic(picName,
                                                        pictureMarkerSym.Size,
                                                        pictureMarkerSym.Angle, rotationField)
        symbolizer.addLayer(New SLDSymbolLayer(graphicSym))
    End Sub
    Private Function getPictureGraphic(picName As String, size As Double, angle As Double,
                                       Optional ByVal rotationField As String = "") As SLDSymbol
        'Dim picName As String = getPictureName(picture, picWidth, picHeight)
        Dim graphicSym As New SLDSymbol("Graphic")
        Dim ExternalGraphicSym As New SLDSymbol("ExternalGraphic")
        Dim resPara As SLdParameter = New SLdParameter("xlink:href", picName, True, "OnlineResource")
        resPara.addOtherProperty("xlink:type", "simple")
        ExternalGraphicSym.sldParamOrSymbols.Add(resPara)
        ExternalGraphicSym.sldParamOrSymbols.Add(New SLdParameter("Format", "image/png", True, ""))
        graphicSym.sldParamOrSymbols.Add(ExternalGraphicSym)

        'Dim markSym As New SLDSymbol("Mark")
        'Dim wekkKonwnname As String = getFontWellKnownName(simpleMarkerSym)
        'If (Not String.IsNullOrWhiteSpace(wekkKonwnname)) Then
        '    markSym.sldParamOrSymbols.Add(New SLdParameter("WellKnownName", wekkKonwnname, True))
        'End If
        ' Dim sldcolor As String = getStringForColor(simpleMarkerSym.Color)
        'If Not String.IsNullOrWhiteSpace(sldcolor) Then
        '    Dim fillSym As New SLDSymbol("Fill")
        '    fillSym.sldParamOrSymbols.Add(New SLdParameter("fill", sldcolor))
        '    markSym.sldParamOrSymbols.Add(fillSym)
        'End If
        'graphicSym.sldParamOrSymbols.Add(markSym)
        graphicSym.sldParamOrSymbols.Add(New SLdParameter("Size", SldUnit.MarkerPoint2Pixel(size), True))
        Dim faa As Object = getRotationByFieldAndAngle(angle, rotationField)
        If faa IsNot Nothing Then
            graphicSym.sldParamOrSymbols.Add(faa)
        End If
        'If Math.Abs(angle) > 0 Then
        '    graphicSym.sldParamOrSymbols.Add(New SLdParameter("Rotation", getRotation(angle), True))
        'End If
        Return graphicSym
    End Function
    Private Function getFontWellKnownName(chrMarkerSym As ICharacterMarkerSymbol) As String
        Dim fnt As stdole.IFontDisp = chrMarkerSym.Font
        Dim chrIndex As Integer = chrMarkerSym.CharacterIndex
        Dim hexcode As String = chrIndex.ToString("x8")
        If hexcode.Length > 4 Then
            hexcode = hexcode.Substring(hexcode.Length - 4)
        End If
        '可参考如下设置字体符号，暂时未更改
        '<se:PointSymbolizer>
        '    <se:Graphic>
        '        <se:Mark>
        '            <se:OnlineResource xlink:href="ttf://zhuang_613" xlink:type="simple"/>
        '            <se:Format>ttf</se:Format>
        '            <se:MarkIndex>83</se:MarkIndex>
        '            <se:Fill>
        '                <se:SvgParameter name="fill">#ffffff</se:SvgParameter>
        '            </se:Fill>
        '        </se:Mark>
        '        <se:Size>16</se:Size>
        '        <se:Displacement>
        '            <se:DisplacementX>0</se:DisplacementX>
        '            <se:DisplacementY>-4</se:DisplacementY>
        '        </se:Displacement>
        '    </se:Graphic>
        '  </se:PointSymbolizer>
        Return String.Format("ttf://{0}#0x{1}", fnt.Name, hexcode.PadLeft(4, "0"))
    End Function
    Private Function getWellKnownName(simpleMarkerSym As ISimpleMarkerSymbol) As String
        Dim markStyle As esriSimpleMarkerStyle = simpleMarkerSym.Style
        Select Case markStyle
            Case esriSimpleMarkerStyle.esriSMSCircle
                Return "circle"
            Case esriSimpleMarkerStyle.esriSMSCross
                Return "cross"
            Case esriSimpleMarkerStyle.esriSMSDiamond
                simpleMarkerSym.Angle = 45
                Return "square"
            Case esriSimpleMarkerStyle.esriSMSSquare
                Return "square"
            Case esriSimpleMarkerStyle.esriSMSX
                Return "x"
        End Select
        Return ""
    End Function
    Private Function getPictureName(pic As stdole.IPictureDisp, backgroundColor As IColor,
                                   Optional ByRef picWidth As Integer = 0,
                                    Optional ByRef picHeight As Integer = 0) As String
        '  Dim pic As stdole.IPictureDisp = picMarkerSym.Picture
        _picSetting.PicNo += 1
        'Dim p As New PictureDispConverter()
        Dim img As Image = PictureDispConverter.IPictureDispToImage(pic) ' Image.FromHbitmap(pic.Handle)
        picWidth = img.Width
        picHeight = img.Height
        Dim bmnew As Bitmap = New Bitmap(img)
        If (backgroundColor IsNot Nothing AndAlso
            TypeOf backgroundColor Is IRgbColor) Then
            Dim c As System.Drawing.Color
            If TypeOf backgroundColor Is IRgbColor Then
                Dim rgb As IRgbColor = backgroundColor
                c = System.Drawing.Color.FromArgb(backgroundColor.Transparency, rgb.Red, rgb.Green, rgb.Blue)
            ElseIf TypeOf backgroundColor Is ICmykColor Then

            End If
            bmnew.MakeTransparent(c)
        End If
        Dim fname As String = String.Format("pic_{0}_{1}.png", _picSetting.LayerName, _picSetting.PicNo) ' "pic_" & Guid.NewGuid().ToString.Replace("-", "") & ".png"
        Dim fpath As String = System.IO.Path.Combine(_picSetting.Folder, fname)
        'img.Save(fpath)
        bmnew.Save(fpath, bmnew.RawFormat)
        bmnew.Dispose()
        img.Dispose()
        Return fname
    End Function
#End Region

#Region "copy"
    Private Sub copySymbolizerToSldSymbol(sourceSymbolizer As SLDSymbolizer, targerSymbol As SLDSymbol)
        Dim lyrs As List(Of SLDSymbolLayer) = sourceSymbolizer.layers
        For Each lyr In lyrs
            Dim symbols As List(Of Object) = lyr.SymbolsOrParas
            For Each sym In symbols
                targerSymbol.sldParamOrSymbols.Add(sym)
            Next
        Next
    End Sub
#End Region
End Class
Public Class PictureDispConverter
    Public Shared Function IPictureDispToImage(pic As stdole.IPictureDisp) As Image
        Dim pax As New PictureDispConverterAX
        Return pax.GetImageFromIPictureDisp(pic)
        ' Return Compatibility.VB6.IPictureDispToImage(pic)
    End Function
End Class
Public Class PictureDispConverterAX
    Inherits System.Windows.Forms.AxHost
    Public Sub New()
        MyBase.New("{63109182-966B-4e3c-A8B2-8BC4A88D221C}")
    End Sub

    Public Function GetImageFromIPictureDisp(ByVal objImage As stdole.IPictureDisp) As System.Drawing.Image
        Dim objPicture As System.Drawing.Image
        objPicture = CType(MyBase.GetPictureFromIPicture(objImage), System.Drawing.Image)
        Return objPicture
    End Function
End Class


